/**
 * Copyright (c) 2019 Coder League
 * All rights reserved.
 *
 * File：DiamondRecordsService.java
 * History:
 *         2019年5月30日: Initially created, CJH.
 */
package club.coderleague.ilsp.service.diamondrecords;

import java.util.Date;
import java.util.List;

import javax.validation.ValidationException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import club.coderleague.ilsp.common.domain.enums.DiamondChangedReason;
import club.coderleague.ilsp.common.domain.enums.DiamondRecordType;
import club.coderleague.ilsp.common.domain.enums.EntityState;
import club.coderleague.ilsp.common.exception.MessageInfoException;
import club.coderleague.ilsp.common.exception.MessageWarnException;
import club.coderleague.ilsp.dao.DiamondRecordRefsDao;
import club.coderleague.ilsp.dao.DiamondRecordsDao;
import club.coderleague.ilsp.dao.MembersDao;
import club.coderleague.ilsp.dao.OrdersDao;
import club.coderleague.ilsp.entities.Diamondrecordrefs;
import club.coderleague.ilsp.entities.Diamondrecords;
import club.coderleague.ilsp.entities.Members;
import club.coderleague.ilsp.entities.Orders;

/**
 * 钻石记录Service
 * 
 * @author CJH
 */
@Service
public class DiamondRecordsService {
	
	private @Autowired MembersDao membersDao;
	
	private @Autowired DiamondRecordsDao diamondRecordsDao;
	
	private @Autowired DiamondRecordRefsDao diamondRecordRefsDao;
	
	private @Autowired OrdersDao ordersDao;
	
	/**
	 * 清理过期钻石
	 * 
	 * @author CJH 2019年5月27日
	 */
	public void updateCleanExpireDiamond() {
		List<Members> members = membersDao.findExistsExpireDiamond();
		if (members == null || members.isEmpty()) {
			return;
		}
		for (Members member : members) {
			List<Diamondrecords> diamondrecords = diamondRecordsDao.findExpireByMemberid(member.getEntityid());
			// 过期钻石数
			Integer expirenum = 0;
			for (Diamondrecords diamondrecord : diamondrecords) {
				expirenum += (diamondrecord.getRemaineddiamond() - diamondrecord.getLockeddiamond());
				diamondrecord.setRemaineddiamond(diamondrecord.getLockeddiamond());
			}
			
			Diamondrecords diamondrecord = new Diamondrecords(EntityState.VALID.getValue(), member.getEntityid(), DiamondRecordType.PAY.getValue(), 
					DiamondChangedReason.EXPIRE.getValue(), null, "过期自动清除", expirenum, null, null, new Date());
			diamondRecordsDao.save(diamondrecord);
		}
	}
	
	/**
	 * 锁定钻石
	 * 
	 * @author CJH 2019年5月31日
	 * @param memberid 会员标识
	 * @param locknum 锁定钻石
	 */
	public void updateLockDiamondByMemberid(Long memberid, Integer locknum) {
		// 校验参数有效性
		if (memberid == null) {
			throw new ValidationException("会员标识不能为空");
		}
		if ((locknum = locknum != null ? locknum : 0) <= 0) {
			throw new ValidationException("锁定钻石不能小于等于0");
		}
		
		// 查询有效钻石并校验有效性
		List<Diamondrecords> diamondrecords = diamondRecordsDao.findValidByMemberid(memberid);
		if (diamondrecords == null || diamondrecords.isEmpty()) {
			throw new MessageInfoException("钻石余额不足");
		}
		Integer lacknum = locknum;
		for (Diamondrecords diamondrecord : diamondrecords) {
			if ((lacknum -= (diamondrecord.getRemaineddiamond() - diamondrecord.getLockeddiamond())) <= 0) {
				break;
			}
		}
		if (lacknum > 0) {
			throw new MessageInfoException("钻石余额不足");
		}
		
		// 锁定钻石
		for (Diamondrecords diamondrecord : diamondrecords) {
			Integer usablenum = diamondrecord.getRemaineddiamond() - diamondrecord.getLockeddiamond();
			Integer thislocknum = locknum > usablenum ? usablenum : locknum;
			diamondrecord.setLockeddiamond(diamondrecord.getLockeddiamond() + thislocknum);
			if ((locknum -= thislocknum) == 0) {
				break;
			}
		}
	}
	
	/**
	 * 解锁锁定钻石
	 * 
	 * @author CJH 2019年5月31日
	 * @param memberid 会员标识
	 * @param unlocknum 解锁钻石
	 */
	public void updateUnlockDiamondByMemberid(Long memberid, Integer unlocknum) {
		// 校验参数有效性
		if (memberid == null) {
			throw new ValidationException("会员标识不能为空");
		}
		if ((unlocknum = unlocknum != null ? unlocknum : 0) <= 0) {
			throw new ValidationException("解锁钻石不能小于等于0");
		}
		
		// 查询已锁定钻石并校验有效性
		List<Diamondrecords> diamondrecords = diamondRecordsDao.findLockedByMemberid(memberid);
		if (diamondrecords == null || diamondrecords.isEmpty()) {
			throw new MessageInfoException("锁定钻石余额不足");
		}
		Integer lacknum = unlocknum;
		for (Diamondrecords diamondrecord : diamondrecords) {
			if ((lacknum -= diamondrecord.getLockeddiamond()) <= 0) {
				break;
			}
		}
		if (lacknum > 0) {
			throw new MessageInfoException("锁定钻石余额不足");
		}
		
		// 解锁锁定钻石
		Integer expirenum = 0;
		for (int i = diamondrecords.size() - 1; i >= 0; i--) {
			Diamondrecords diamondrecord = diamondrecords.get(i);
			Integer thisunlocknum = unlocknum > diamondrecord.getLockeddiamond() ? diamondrecord.getLockeddiamond() : unlocknum;
			diamondrecord.setLockeddiamond(diamondrecord.getLockeddiamond() - thisunlocknum);
			
			// 校验钻石有效性
			if (diamondRecordsDao.isExpireByEntityid(diamondrecord.getEntityid())) {
				expirenum += (diamondrecord.getRemaineddiamond() - diamondrecord.getLockeddiamond());
				diamondrecord.setRemaineddiamond(diamondrecord.getLockeddiamond());
			}
			
			if ((unlocknum -= thisunlocknum) == 0) {
				break;
			}
		}
		if (expirenum > 0) {
			Diamondrecords diamondrecord = new Diamondrecords(EntityState.VALID.getValue(), memberid, DiamondRecordType.PAY.getValue(), 
					DiamondChangedReason.EXPIRE.getValue(), null, "解除锁定过期清除", expirenum, null, null, new Date());
			diamondRecordsDao.save(diamondrecord);
		}
	}
	
	/**
	 * 使用钻石
	 * 
	 * @author CJH 2019年5月31日
	 * @param orderid 订单标识
	 * @param usenum 使用钻石
	 */
	public void updateUseDiamondByOrderid(Long orderid, Integer usenum) {
		// 校验参数有效性
		if (orderid == null) {
			throw new ValidationException("订单标识不能为空");
		}
		if ((usenum = usenum!= null ? usenum : 0) <= 0) {
			throw new ValidationException("使用钻石不能小于等于0");
		}
		
		// 查询锁定钻石并验证有效性
		Orders order = ordersDao.getOne(orderid);
		List<Diamondrecords> diamondrecords = diamondRecordsDao.findLockedByMemberid(order.getMemberid());
		if (diamondrecords == null || diamondrecords.isEmpty()) {
			throw new MessageInfoException("锁定钻石余额不足");
		}
		Integer lacknum = usenum;
		for (Diamondrecords diamondrecord : diamondrecords) {
			if ((lacknum -= diamondrecord.getLockeddiamond()) <= 0) {
				break;
			}
		}
		if (lacknum > 0) {
			throw new MessageInfoException("锁定钻石余额不足");
		}
		
		// 保存使用钻石记录
		Diamondrecords newdiamondrecord = new Diamondrecords(EntityState.VALID.getValue(), order.getMemberid(), DiamondRecordType.PAY.getValue(), 
				DiamondChangedReason.PAY.getValue(), orderid, new StringBuilder("订单抵扣(订单号：").append(orderid).append(")").toString(), 
				usenum, null, null, new Date());
		diamondRecordsDao.save(newdiamondrecord);
		
		// 使用钻石
		for (Diamondrecords diamondrecord : diamondrecords) {
			Integer thisusenum = usenum > diamondrecord.getLockeddiamond() ? diamondrecord.getLockeddiamond() : usenum;
			diamondrecord.setRemaineddiamond(diamondrecord.getRemaineddiamond() - thisusenum);
			diamondrecord.setLockeddiamond(diamondrecord.getLockeddiamond() - thisusenum);
			diamondRecordRefsDao.save(new Diamondrecordrefs(EntityState.VALID.getValue(), newdiamondrecord.getEntityid(), 
					diamondrecord.getEntityid(), thisusenum, 0));
			if ((usenum -= thisusenum) == 0) {
				break;
			}
		}
	}
	
	/**
	 * 退款钻石
	 * 
	 * @author CJH 2019年8月25日
	 * @param orderid 订单标识
	 * @param refundnum 退款钻石
	 */
	public void updateRefundDiamondByOrderid(Long orderid, Integer refundnum) {
		// 校验参数有效性
		if (orderid == null) {
			throw new ValidationException("订单标识不能为空");
		}
		if ((refundnum = refundnum!= null ? refundnum : 0) <= 0) {
			throw new ValidationException("退款钻石不能小于等于0");
		}
		
		// 查询钻石使用记录
		Diamondrecords paymentdiamondrecord = diamondRecordsDao.findByOrderidAndRecordtype(orderid, DiamondRecordType.PAY.getValue());
		if (paymentdiamondrecord == null) {
			throw new MessageWarnException("未找到钻石支付记录");
		}
		List<Diamondrecordrefs> diamondrecordrefs = diamondRecordRefsDao.findByPaymentrecordid(paymentdiamondrecord.getEntityid());
		if (diamondrecordrefs == null || diamondrecordrefs.isEmpty()) {
			throw new MessageWarnException("未找到钻石支付记录关系");
		}
		
		// 退款钻石
		Integer expirenum = 0;
		for (int i = diamondrecordrefs.size() - 1; i >= 0; i--) {
			Diamondrecordrefs diamondrecordref = diamondrecordrefs.get(i);
			Integer thisrefundnum = refundnum > diamondrecordref.getPaymentamount() ? diamondrecordref.getPaymentamount() : refundnum;
			diamondrecordref.setRefundamount(thisrefundnum);
			
			Diamondrecords incomediamondrecord = diamondRecordsDao.getOne(diamondrecordref.getIncomerecordid());
			incomediamondrecord.setRemaineddiamond(incomediamondrecord.getRemaineddiamond() + thisrefundnum);
			
			// 校验钻石有效性
			if (diamondRecordsDao.isExpireByEntityid(incomediamondrecord.getEntityid())) {
				expirenum += (incomediamondrecord.getRemaineddiamond() - incomediamondrecord.getLockeddiamond());
				incomediamondrecord.setRemaineddiamond(incomediamondrecord.getLockeddiamond());
			}
			
			if ((refundnum -= thisrefundnum) == 0) {
				break;
			}
		}
		if (expirenum > 0) {
			Diamondrecords diamondrecord = new Diamondrecords(EntityState.VALID.getValue(), paymentdiamondrecord.getMemberid(), DiamondRecordType.PAY.getValue(), 
					DiamondChangedReason.EXPIRE.getValue(), null, "退款过期清除", expirenum, null, null, new Date());
			diamondRecordsDao.save(diamondrecord);
		}
	}
	
	/**
	 * 收入钻石
	 * 
	 * @author CJH 2019年6月17日
	 * @param orderid 订单标识
	 * @param incomenum 收入钻石
	 * @param changedreason 变化原因
	 * @param reasondesc 原因描述
	 */
	public void updateIncomeDiamondByOrderid(Long orderid, Integer incomenum, DiamondChangedReason changedreason, String reasondesc) {
		// 校验参数有效性
		if (orderid == null) {
			throw new ValidationException("订单标识不能为空");
		}
		if ((incomenum = incomenum != null ? incomenum : 0) <= 0) {
			throw new ValidationException("收入钻石不能小于等于0");
		}
		if (changedreason == null || !DiamondRecordType.INCOME.equals(changedreason.getType())) {
			throw new ValidationException("变化原因无效");
		}
		
		Orders orders = ordersDao.getOne(orderid);
		Diamondrecords diamondrecords = new Diamondrecords(EntityState.VALID.getValue(), orders.getMemberid(), DiamondRecordType.INCOME.getValue(), 
				changedreason.getValue(), orderid, reasondesc, incomenum, incomenum, 0, new Date());
		diamondRecordsDao.save(diamondrecords);
	}
}
